home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Magnum One
/
Magnum One (Mid-American Digital) (Disc Manufacturing).iso
/
d12
/
cimcat.arc
/
CIMCAT.C
next >
Wrap
Text File
|
1990-03-21
|
14KB
|
469 lines
/* Program CISCAT
This program reads each file in a directory that has an extension
of *.THD
These files are the downloaded threads from the new CompuServe
CIM (Compuserve Information Manager<tm>) program. Each will have
one or more messages, all the same subject.
Purpose of this program is to build a single ASCII output file
containing ASCII versions of these messages, as if a person had
read the messages in ASCII and captured the stream (IE, using the
"RTN" command to a capture file).
Michael Gordon
*/
#define STDOUT 1
#include <stdlib.h>
#include <stdio.h>
#include <dir.h>
#include <dos.h>
#include <string.h>
#include <io.h>
#include <alloc.h>
#include <ctype.h>
#include <fcntl.h>
#define TRUE 1
#define FALSE 0
#define INBUFSIZE (unsigned)30720 /* input buffer (60 sectors) */
#define OUTBUFSIZE (unsigned)6000 /* output buffer (for 10 sectors) */
typedef enum {NOFLUSH, FLUSHAFTER, FLUSH};
/* description of *.THD files as determined by inspection.
char version[7] = "VIS000\x1A";
int unk1; = 75 = 0x4B
char unk2 = 3;
char hdate1[6]; 6 bytes: sec min hr day month year-76
char hdate2[6]; ditto. why 2?
long unk3 = 0x75; ?
-- variable length fields --
[size byte=n][string of n-bytes] topic/subject
[size byte=n][string of n-bytes] section
[size byte=n][string of n-bytes] forum
[size byte=n][string of n-bytes] forum short name (DOS subdir name)
-- now a DOS information block --
int = n skip forward n bytes to skip to message block
| char = 1
| [size byte=n][string of n-bytes] directory name
| long = file number. Converted to hex digits, lz supp, = file name.
| [size byte=n][string of n-bytes] forum name (why again?)
`-> begin message block
-------------------- repeated for each message -------------------------
int n = 0000 reverse link? status?
int textmsg = nnnn bytes to add to addr this word to find text-2
| long msgnumber this message's number
| long parent message number of parent msg
| long reply message number of first reply
| long reply2 ?
| char number_replies
| char msg_date[6] 6 byte date-time
| char msg_date[6] ditto. why 2?
| [size byte=n][string of n-bytes] From: name
| [size byte=n][string of n-bytes] From: ID
| [size byte=n][string of n-bytes] TO: name
| [size byte=n][string of n-bytes] TO: ID
| char = x status byte?
`int nextmsg (text-2) bytes to add to this addr to get next msg block
also, (nextmsg-2)= size of message body
char text[nextmsg-2] body of message
-------------------------------------------------------------------- */
/* the header is fixed. After the header, things must be parsed. */
struct {
char version[7]; /* "VIS000\x1A" */
int unk1;
char unk2;
char hdate1[6]; /* 6 bytes: sec min hr day month year-76 */
char hdate2[6]; /* ditto. why 2? */
unsigned int sec_forum_ptr; /* address of section, forum strings */
int unk3;
} * theader;
char subject[40];
char section[40];
char forum[40];
char toname[40];
char touid[40];
char fromname[40];
char fromuid[40];
char statusbyte;
char numreplies;
char mdate1[6];
char mdate2[6];
char datestring[40];
char *months[14]={"???","Jan","Feb","Mar","Apr","May","Jun","Jul",
"Aug","Sep","Oct","Nov","Dec","???"};
unsigned int reverselink;
char * bodybegins;
char * nextmsg;
char * lid; /* stop when just < this address */
long msg_number;
long parent;
long reply;
long reply2;
int inhandle; /* which one are we using */
int totalmsgs;
unsigned int bytesin; /* bytes in inbuffer */
unsigned int bytesout; /* bytes in out buffer */
unsigned buffersize; /* for search buffer and index */
char finder[] = "????????.THD";
char crlf[] = {13,10,13,10,13,10,0};
char * inbuffer;
char * outbuffer;
char * outpointer;
union {
char * c;
unsigned int *w;
long * l;
} parser;
void write_bytes(char * instring, int numbytes)
{
int i;
for (i=0;i<numbytes;i++)
{ *outpointer = *instring;
bytesout++;
instring++;
outpointer++;
if (bytesout>=5120)
{ _write(STDOUT,outbuffer,bytesout);
bytesout=0;
outpointer=outbuffer;
}
}
}
void parsemessages(void)
{
int i;
char ch;
char * endline;
char temps[40];
unsigned bytesintext;
unsigned bytestowrite;
int numintopic;
/* header structure already pointing at the buffer beginning */
/* find and build the SUBJECT, SECTION, FORUM line */
numintopic=0;
parser.c = inbuffer + sizeof(theader[0]);
memset(subject,0,sizeof(subject));
memcpy(subject,parser.c+1,*parser.c); /* copies subject */
parser.c += *parser.c;
parser.c ++; /* point to section */
_write(2,subject,strlen(subject)); /* report progress */
_write(2," ________________________________________",
40-strlen(subject)); /* sort of a "tab" stop */
memset(section,0,sizeof(section));
memcpy(section,parser.c+1,*parser.c); /* copies subject */
parser.c += *parser.c;
parser.c ++; /* point to forum name */
memset(forum,0,sizeof(forum));
memcpy(forum,parser.c+1,*parser.c); /* copies subject */
parser.c += *parser.c;
parser.c ++; /* point to directory name */
parser.c += *parser.c; /* skip for now */
parser.c ++; /* point to forum name */
parser.c += *parser.w; /* skip more text (DOS block) */
do
{
/* now pointing into a message block */
numintopic++;
totalmsgs++;
reverselink = *parser.w;
parser.c +=2;
bodybegins = ( *parser.w) + parser.c; /* abs address */
parser.c +=2;
msg_number = *parser.l;
parser.c +=4;
parent = *parser.l;
parser.c +=4;
reply = *parser.l;
parser.c +=4;
reply2 = *parser.l;
parser.c +=4;
numreplies = *parser.c;
parser.c ++;
memcpy(mdate1,parser.c,6);
parser.c +=6;
memcpy(mdate2,parser.c,6);
parser.c +=6;
memset(fromname,0,sizeof(fromname));
memcpy(fromname,parser.c+1,*parser.c);
parser.c += *parser.c;
parser.c++;
memset(fromuid,0,sizeof(fromuid));
memcpy(fromuid,parser.c+1,*parser.c);
parser.c += *parser.c;
parser.c++;
memset(toname,0,sizeof(toname));
memcpy(toname,parser.c+1,*parser.c);
parser.c += *parser.c;
parser.c++;
memset(touid,0,sizeof(touid));
memcpy(touid,parser.c+1,*parser.c);
parser.c += *parser.c;
parser.c++;
statusbyte = *parser.c;
parser.c=bodybegins; /* reset */
nextmsg = bodybegins + *parser.w;
bytesintext = ( *parser.w) -2;
parser.c +=2;
/* write the header stuff to stdout */
write_bytes("#: ",3);
ltoa(msg_number,temps,10);
write_bytes(temps,strlen(temps));
write_bytes(" S?/",4);
write_bytes(section,strlen(section));
write_bytes(crlf,2);
sprintf(datestring," %02d-%s-%04d %02d:%02d:%02d",
mdate1[3],months[mdate1[4]],mdate1[5]+1980,
mdate1[2],mdate1[1],mdate1[0]);
write_bytes(datestring,strlen(datestring));
write_bytes(crlf,2);
write_bytes("SB: ",4);
if (parent)
{ ltoa(parent,temps,10);
write_bytes("#",1);
write_bytes(temps,strlen(temps));
write_bytes("-",1);
}
write_bytes(subject,strlen(subject));
write_bytes(crlf,2);
write_bytes("Fm: ",4);
write_bytes(fromname,strlen(fromname));
write_bytes(" ",1);
write_bytes(fromuid,strlen(fromuid));
write_bytes(crlf,2);
write_bytes("To: ",4);
write_bytes(toname,strlen(toname));
write_bytes(" ",1);
write_bytes(touid,strlen(touid));
if (statusbyte & 0x08)
write_bytes(" (X)",4);
write_bytes(crlf,4);
/* now we are ready to parse the text. */
/* this is the slow way but gets the job done for now */
do
{
if (bytesintext <79)
{
bytestowrite = bytesintext;
}
else
{
endline = parser.c + 78;
/* locate a suitable end of line */
while ((*endline!=' ') && (endline > parser.c)) endline--;
if (endline==parser.c) /* couldn't find a break */
endline=parser.c + 77; /* so reset to 78 */
bytestowrite = (endline - parser.c) + 1;
}
/* write the line, checking for paragraph markers and
lonely linefeeds. On paragraph marker, just break out
of the write loop and let it hit the crlf write. This
will automatically cause a new line of 78 to be parsed.
If hit CR or LF, close out the line, too; and make sure
that a CRLF combination doesn't cause the next line to
start with the remnant LF. */
for (i=0;i<bytestowrite;i++)
{ ch=*parser.c;
parser.c++;
bytesintext--;
if ((ch==0x40) && (*parser.c==0x62))
{ /* paragraph marker */
parser.c++; /* skip the 'b' */
break; /* then break to the crlf write */
}
else
{
if (ch==13)
{ if (*parser.c==10) /* dump the crlf sequence */
{ parser.c++;
break;
}
break; /* dump just the cr */
}
if (ch==10) break; /* can't be a preceeding cr */
write_bytes(&ch,1);
}
} /* end of line write loop */
write_bytes(crlf,2);
} while ((parser.c < nextmsg) &&
(parser.c < lid) &&
(bytesintext>0));
/* while lines exist in this msg */
write_bytes(crlf,4);
/* here show in output file how many replies # msg number of
the first reply. */
if (reply)
{ itoa(numreplies,temps,10);
write_bytes(" ",10);
write_bytes(temps,strlen(temps));
if (numreplies==1) write_bytes(" reply (",8);
else write_bytes(" replies (",10);
ltoa(reply,temps,10);
write_bytes(temps,strlen(temps));
if (reply==1) write_bytes(")",1);
else write_bytes(",...)",5);
write_bytes(crlf,4);
}
parser.c = nextmsg; /* ensure alignment (failed before this) */
} while ((parser.c < lid) && (nextmsg < (lid-sizeof(theader[0]))));
/* while more messages are in thread */
itoa(numintopic,temps,10);
_write(2,temps,strlen(temps)); /* report progress */
_write(2," ",6-strlen(temps));
itoa(totalmsgs,temps,10);
_write(2,temps,strlen(temps)); /* report progress */
_write(2,crlf,2);
}
void scan(void)
{
/*
4E Find FIRST file.
On entry, DS:DX points to ASCIIZ with logged_drive, path, and filename.
CX=attribute for searching.
4F Find NEXT matching file.
Current DTA must contain info previously filled by Find FIRST (4E).
Error code 18 (decimal) returned if no more sources.
*/
/* static struct REGPACK regs; */
/*
unsigned r_ax, r_bx, r_cx, r_dx;
unsigned r_bp, r_si, r_di, r_ds, r_es, r_flags;
*/
struct ffblk ffblk;
/*
char logged_drive; do not change
char pattern[13]; these fields,
char reserved[7]; Microsoft reserved
char ff_attrib;
short ff_ftime;
short ff_fdate;
long ff_fsize;
char ff_name[13]; result of the search, asciiz
used with DOS functions 4E, 4F */
int ret;
char temps[33];
ret=findfirst(finder,&ffblk,0);
if (ret)
{ puts("No Files found");
exit(0);
}
do
{ /* find next. report progress to STD ERR; incl file handle */
_write(2,ffblk.ff_name,strlen(ffblk.ff_name)); /* show progress */
_write(2," ",2);
inhandle=_open(ffblk.ff_name,0);
if (inhandle>0)
{ bytesin=_read(inhandle,inbuffer,buffersize);
if ((bytesin >0) && (memcmp(inbuffer,"VIS",3)==0))
{
lid = inbuffer + bytesin;
parsemessages();
}
_close(inhandle);
}
ret=findnext(&ffblk);
} while (!ret);
}
void main(void)
{
inbuffer=farmalloc(INBUFSIZE);
buffersize=INBUFSIZE;
if (inbuffer==NULL)
{ puts("Not enough memory for input buffer");
printf("Amount asked for %u bytes \n",INBUFSIZE);
printf("Amount in system %lu bytes \n",farcoreleft());
exit(1);
}
memset(inbuffer,0,buffersize);
theader=inbuffer; /* point to the header structure */
outbuffer=farmalloc(OUTBUFSIZE);
if (outbuffer==NULL)
{ puts("Not enough memory for input buffer");
printf("Amount asked for %u bytes \n",OUTBUFSIZE);
printf("Amount in system %lu bytes \n",farcoreleft());
exit(1);
}
memset(outbuffer,0,OUTBUFSIZE);
bytesout=0;
outpointer=outbuffer;
_write(2,"CIMCAT version 1.1",18);
_write(2,crlf,4);
scan();
if (bytesout)
{ _write(STDOUT,outbuffer,bytesout);
bytesout=0;
outpointer=outbuffer;
}
}